<?php

namespace Tests;

use App\Models\Administrator;
use Facebook\WebDriver\Chrome\ChromeOptions;
use Facebook\WebDriver\Exception\NoSuchElementException;
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Illuminate\Support\Facades\Auth;
use Laravel\Dusk\TestCase as BaseTestCase;
use Laravel\Dusk\Browser;

abstract class DuskTestCase extends BaseTestCase
{
    use CreatesApplication;

    /**
     * Prepare for Dusk test execution.
     *
     * @beforeClass
     * @return void
     */
    public static function prepare()
    {
        if (!static::runningInSail()) {
            static::startChromeDriver();
        }
    }

    /**
     * Create the RemoteWebDriver instance.
     *
     * @return \Facebook\WebDriver\Remote\RemoteWebDriver
     */
    protected function driver()
    {
        $options = (new ChromeOptions)->addArguments(collect([
            $this->shouldStartMaximized() ? '--start-maximized' : '--window-size=1920,1080',
            '--disable-gpu',
            '--headless',
            '--no-sandbox',
            '--disable-dev-shm-usage',
            '--disable-software-rasterizer',

        ])->unless($this->hasHeadlessDisabled(), function ($items) {
            return $items->merge([
                '--disable-gpu',
                '--headless',
            ]);
        })->all());

        return RemoteWebDriver::create(
            $_ENV['DUSK_DRIVER_URL'] ?? 'http://localhost:9515',
            DesiredCapabilities::chrome()->setCapability(
                ChromeOptions::CAPABILITY, $options
            )
        );
    }

    /**
     * Determine whether the Dusk command has disabled headless mode.
     *
     * @return bool
     */
    protected function hasHeadlessDisabled()
    {
        return isset($_SERVER['DUSK_HEADLESS_DISABLED']) ||
            isset($_ENV['DUSK_HEADLESS_DISABLED']);
    }

    /**
     * Determine if the browser window should start maximized.
     *
     * @return bool
     */
    protected function shouldStartMaximized()
    {
        return isset($_SERVER['DUSK_START_MAXIMIZED']) ||
            isset($_ENV['DUSK_START_MAXIMIZED']);
    }

    /**
     * @param Browser $browser
     * @param $user
     * @return Browser
     * @throws \Facebook\WebDriver\Exception\TimeOutException
     */
    protected function loginWithUser(Browser $browser, $user): Browser
    {

        $browser->visit('/admin/auth/login');

        $loginLink = $this->doesElementExist($browser,'.btn.btn-primary.float-right.login-btn');

        if ($loginLink) {
            $browser->visit('/admin/auth/login')
                ->screenshot('login/login')
                ->type('username', $user->username)
                ->type('password', 'admin')
                ->press('Login')
                ->screenshot('login/login.submit')
                ->waitForLocation('/admin', 3)
                ->screenshot('admin/index')
                ->assertPathIs('/admin');
        }
        return $browser;
    }

    /**
     * @param Browser $browser
     * @return Browser
     * @throws \Facebook\WebDriver\Exception\TimeOutException
     */
    protected function loginWithAdmin(Browser $browser): Browser
    {
        if (empty($admin = Administrator::first())) {
            $admin = Administrator::factory()->administrator()->create();
        }

        $this->assertNotNull($admin);

        return $this->loginWithUser($browser,$admin);
    }

    /**
     * @return void
     * @throws \Throwable
     */
    protected function loginAdmin()
    {
        $this->browse(function (Browser $browser) {

            $this->loginWithAdmin($browser);
        });
    }

    /**
     * Check if an element exists on the page.
     *
     * @param  Browser  $browser
     * @param  string  $selector
     * @return bool
     */
    protected function doesElementExist(Browser $browser, string $selector): bool
    {
        try {
            $browser->resolver->findOrFail($selector);

            return true;
        } catch (NoSuchElementException $e) {
            return false;
        }
    }
}
